# include "Hero.h"

# include "Game.h"
# include "Renderer.h"
# include "AI.h"

# include "World.h"
# include "Map.h"

# include "ObjectAction.h"
# include "ObjectConnect.h"
# include "Chest.h"

# include "Inventory.h"
# include "Armor.h"
# include "Equipment.h"
# include "Quests.h"
# include "Enemy.h"
# include "PNJ.h"

Hero::Hero() : Personage(), myCamera( 0), myInventory( 0), myAngleCamera( 0), myDistanceCamera( 0), mySpeedCamera( 0), myRotationCamera( 0), myStrength( 0), myAgility( 0), myStamina( 0), myPower( 0), myMana( 0)
{
	myLifeBar = NULL;
	myManaBar = NULL;
	myTarget = NULL;
}

Hero::~Hero()
{
	delete myEquipment;
	delete myInventory;
	
	if ( myCamera )
	{
		myRenderer->deleteCamera( myCamera);
	}

	if ( myCameraNode )
	{
		myRenderer->deleteSceneNode( myCameraNode);
	}
}

void Hero::setLifeBar( CEGUI::ProgressBar* lifeBar)
{
	myLifeBar = lifeBar;
}

void Hero::setManaBar( CEGUI::ProgressBar* manaBar)
{
	myManaBar = manaBar;
}

void Hero::setAction( Action action)
{
	myAction = action;
}

void Hero::setTarget( Enemy* target)
{
	myTarget = target;
}

void Hero::setTalk( PNJ* talk)
{
	myTalk = talk;
}

void Hero::setActionTarget( ObjectAction* actionTarget)
{
	myActionTarget = actionTarget;
}

int Hero::getStrength()
{
	return myStrength;
}

int Hero::getAgility()
{
	return myAgility;
}

int Hero::getStamina()
{
	return myStamina;
}

int Hero::getPower()
{
	return myPower;
}

int Hero::getCurrentMana()
{
	return myManaCurrent;
}

int Hero::getMana()
{
	return myMana;
}

unsigned int Hero::getLevel()
{
	return myLevel;
}

unsigned int Hero::getExperience()
{
	return myExperience;
}

unsigned int Hero::getNextExperience()
{
	return myNextExperience;
}

unsigned int Hero::getPointsCharac()
{
	return myPointsCharac;
}

unsigned int Hero::getPointsPower()
{
	return myPointsPower;
}

Ogre::Camera* Hero::getCamera()
{
	return myCamera;
}

Ogre::SceneNode* Hero::getBodyNode()
{
	return myBodyNode;
}

Inventory* Hero::getInventory()
{
	return myInventory;
}

Equipment* Hero::getEquipment()
{
	return myEquipment;
}

Quests* Hero::getQuests()
{
	return myQuests;
}

PNJ* Hero::getTalk()
{
	return myTalk;
}

void Hero::receiveDamage( const Damage& damage)
{
	myLifeCurrent -= damage.damage;
}

void Hero::receiveExperience( const Experience& experience)
{
	if ( experience.level == 0 )
	{
		myExperience += experience.experience;
	}

	else
	{
		myExperience += experience.experience;	
	}

	if ( myExperience >= myNextExperience )
	{
		myExperience -= myNextExperience;
		myLevel++;
		
		myPointsCharac += 5;
		myPointsPower += 3;
		
		myNextExperience += INCREMENT * myLevel;	
	}
}

bool Hero::isDead()
{
	if ( myLifeCurrent <= 0 )
	{
		return true;
	}

	return false;
}

void Hero::init( Game* game, Renderer* renderer, AI* ai, World* world, Map* map)
{
	Personage::init( renderer);
	
	myGame = game;
	myAI = ai;
	myWorld = world;
	myMap = map;

	myDistanceCamera = 1000.0f;
	myAngleCamera = 45.0f;
	mySpeedCamera = 0.0f;
	myRotationCamera = 0.0f;

	mySize = 20.0f;

	myInventory = new Inventory();

	myEquipment = new Equipment();
	myEquipment->init( myRenderer, this);

	myQuests = new Quests();
	myQuests->init( world, this, "Resources/Lua/Quests.lua");

	myLoaded = false;
}

void Hero::createNewHero()
{
	if ( !myLoaded )
	{
		mySceneNode = myRenderer->createSceneNode( "HeroNode");

		myBodyNode = mySceneNode->createChildSceneNode( "BodyNode");
		myBody = myRenderer->createEntity( "HeroBody", "perso2.mesh");
		myBody->setQueryFlags( ME_FLAG);
		myBodyNode->attachObject( myBody);

		myCamera = myRenderer->createCamera( "HeroCamera");
		myCameraNode = mySceneNode->createChildSceneNode( "CameraNode");
		myCameraNode->attachObject( myCamera);
		myCameraNode->setPosition( Ogre::Vector3( cos( myAngleCamera) * ( 100 + sqrt( pow( myDistanceCamera, 2) / 5)), 2 * sqrt( pow( myDistanceCamera, 2) / 5), sin( myAngleCamera) * ( 100 + sqrt( pow( myDistanceCamera,2) / 5))));
		myCamera->lookAt( mySceneNode->getPosition());

		myLoaded = true;
	}

	myViewport = myRenderer->createViewport( myCamera);
	myViewport->setBackgroundColour( Ogre::ColourValue( 0.0f, 0.0f, 0.0f));
	myCamera->setAspectRatio( Ogre::Real( myViewport->getActualWidth()) / Ogre::Real( myViewport->getActualHeight()));
	
	myAction = NOTHING;

	myStrength = 10;
	myAgility = 10;
	myStamina = 10;
	myPower = 10;
	
	myLife = myStamina * 10;
	myLifeCurrent = myLife;
	myMana = myPower * 10;
	myManaCurrent = myMana; 

	myLevel = 1;
	myExperience = 0;
	myNextExperience = 100;
	myPointsCharac = 0;
	myPointsPower = 0;
}

void Hero::updateWorld()
{
	for ( unsigned int i = 0; i < myPNJTalked.size(); i++ )
	{
		PNJ* pnjTmp = myWorld->findPNJName( *myPNJTalked[i]);
		
		if ( pnjTmp )
		{
			pnjTmp->setCurrentDialog( "Second Welcome");
		}
	}
}

void Hero::oneFrame( Ogre::Real time)
{	
	myLifeBar->setProgress( (float) myLifeCurrent / (float) myLife);
	myManaBar->setProgress( (float) myManaCurrent / (float) myMana);
	
	myTimeAction -= time;

	if ( myTimeAction < 0.0f )
	{
		myTimeAction = 0.0f;
	}
	
	if ( myAction == GO || myAction == GO_HIT || myAction == GO_TALK || myAction == GO_ACTION )
	{
		Ogre::Real moveTmp = mySpeed * time;
		myDistances.top() -= moveTmp;

		mySceneNode->translate( myDirections.top() * moveTmp);

		if ( myDistances.top() < 0.0f )
		{	
			myDistances.pop();
			myDirections.pop();

			if ( !myDirections.size() )
			{
				if ( myAction == GO )
				{
					myDirection = Ogre::Vector3::ZERO;
					myAction = NOTHING;
				}

				else if ( myAction == GO_HIT )
				{
					myDirection = Ogre::Vector3::ZERO;
					myAction = HIT;
				}

				else if ( myAction == GO_TALK )
				{
					myDirection = Ogre::Vector3::ZERO;
					myAction = TALK;
				}

				else if ( myAction == GO_ACTION )
				{
					myDirection = Ogre::Vector3::ZERO;
					myAction = ACTION;
				}
			}
		}
		
		else
		{
			if ( myTarget )
			{
				myAI->findDirection( myTarget);
			}
		}		
	}

	else if ( myAction == HIT )
	{
		if ( (myTarget->getPosition() - getPosition()).length() > (myTarget->getSize() + getSize()) )
		{
			myAI->findDirection( myTarget);
		}
		
		else if ( myTimeAction <= 0.0f )
		{
			Damage damageTmp;
			damageTmp.damage = 25;
			
			myTarget->receiveDamage( damageTmp);
			myTarget = NULL;
			myAction = NOTHING;

			myTimeAction = 0.250f;
		}
	}

	else if ( myAction == TALK )
	{		
		bool addTarget = true;
		
		for ( unsigned int i = 0; i < myPNJTalked.size(); i++ )
		{
			if ( *myPNJTalked[i] == myTalk->getName() )
			{
				addTarget = false;
			}
		}

		if ( addTarget )
		{
			myPNJTalked.push_back( new std::string( myTalk->getName()));
		}
		
		Event evtTmp;

		evtTmp.message = OPEN_TALK;
		myGame->receiveEvent( evtTmp);
		
		myAction = NOTHING;
	}

	else if ( myAction == ACTION )
	{
		myAction = NOTHING;
		
		switch ( myActionTarget->getActionType() )
		{
			case CONNECT_MAP:
			myGame->changeWorld( ((ObjectConnect*) myActionTarget)->getNextWorld());
			break;

			case CHEST:
			((Chest*)myActionTarget)->open();
			break;

			case OBJECT:
			myInventory->add( (ObjectPickUp*) myActionTarget);
			myMap->deleteObjectPickUp( (ObjectPickUp*) myActionTarget);
			break;
		}

		myActionTarget = NULL;
	}

	if ( mySpeedCamera != 0.0f )
	{
		if ( myDistanceCamera < 200.0f )
		{
			myDistanceCamera = 200.0f;
			mySpeedCamera = 0.0f;
		}

		if ( myDistanceCamera > 1500.0f )
		{
			myDistanceCamera = 1500.0f;
			mySpeedCamera = 0.0f;
		}
		
		myDistanceCamera += mySpeedCamera * time;
		myCameraNode->setPosition( Ogre::Vector3( cos( myAngleCamera) * ( 100 + sqrt( pow( myDistanceCamera, 2) / 5)), 2 * sqrt( pow( myDistanceCamera, 2) / 5), sin( myAngleCamera) * ( 100 + sqrt( pow( myDistanceCamera,2) / 5))));
		myCamera->lookAt( mySceneNode->getPosition());
	}

	if ( myRotationCamera != 0.0f )
	{
		myAngleCamera += myRotationCamera * time;

		if ( myAngleCamera < 0.0f )
		{
			myAngleCamera += 360.0f;
		}
		
		if ( myAngleCamera > 360.0f )
		{
			myAngleCamera -= 360.0f;
		}

		myCameraNode->setPosition( Ogre::Vector3( cos( myAngleCamera) * ( 100 + sqrt( pow( myDistanceCamera, 2) / 5)), 2 * sqrt( pow( myDistanceCamera, 2) / 5), sin( myAngleCamera) * ( 100 + sqrt( pow( myDistanceCamera,2) / 5))));
		myCamera->lookAt( mySceneNode->getPosition());
	}
}

void Hero::zoom()
{
	mySpeedCamera = -300.0f;
}

void Hero::deZoom()
{
	mySpeedCamera = 300.0f;
}

void Hero::stopZoom()
{
	mySpeedCamera = 0.0f;
}

void Hero::rotateClock()
{
	myRotationCamera = -2.5f;
}

void Hero::rotateCounterClock()
{
	myRotationCamera = 2.5f;
}

void Hero::rotateStop()
{
	myRotationCamera = 0.0f;
}

void Hero::equipWeapon( const std::string& name)
{
	Weapon* weaponTmp = myInventory->findWeapon( name);
	myEquipment->equip( weaponTmp);
}

void Hero::equipShield( const std::string& name)
{
	Shield* shieldTmp = myInventory->findShield( name);
	myEquipment->equip( shieldTmp);
}

void Hero::equipArmor( const std::string& name)
{
	Armor* armorTmp = myInventory->findArmor( name);
	myEquipment->equip( armorTmp);
}

void Hero::equipJewel( const std::string& name)
{
	Jewel* jewelTmp = myInventory->findJewel( name);
	myEquipment->equip( jewelTmp);
}

void Hero::addExperience( unsigned int experience)
{
	myExperience += experience;

	if ( myExperience >= myNextExperience )
	{
		myExperience -= myNextExperience;
		myLevel++;
		
		myPointsCharac += 5;
		myPointsPower += 3;
		
		myNextExperience += INCREMENT * myLevel;	
	}
}
